/**
 * @class   wosh::Thread
 * @brief   Abstract class providing thread-subsystem (multiplatform, based
 *          on QThread (QT)
 *
 *
 * \par Generic Therading-Architecture notes
 *  A generic process has an address space and a single (parent) thread of control.
 *  Different threads in a process share the same address space (so we have a
 *  local-global shared memory).
 *  On uniprocessor machines, threads are processed using timesharing.
 *
 *
 * wosh::Thread class is the common underlying component of WOSH threads,
 * the base implementation cooperates transparently with core-module wosh::ThreadManager.
 * Self-(un)registration and notifies state-changes.
 *
 *
 * Here is a snipped of a generic thread-implementation:
 * \code
class MyThreadImplementation : public wosh::Thread
 {
	WOSH_CLASSNAME(wosh::MyThreadImplementation)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MyThreadImplementation() : ThreadImpl(NULL, "MyThreadImplementation.Thread") { }
		~MyThreadImplementation() {
			if ( isThreadRunning() )
				quitThread();
		 }

	public:
		bool initializeThread() {
			if ( this->parent == NULL ) return false;
			if ( !myComponent.init() ) return false;
			return true;
		 }
		void runThread() {
			while(this->running) {
				if ( !waitForMSec(1000) )
					break;
				myComponent.process();
			 }
		 }
		void exitingThread() {
			myComponent.deinit();
		 }

	private:
		MyComponent myComponent;
 };
 * \endcode
 *
 * Functions \c initializeThread(), \c runThread(), \c exitingThread() are called within the new OS-thread
 * in this relative order.
 *
 * \c initializeThread() method is also a sort of validator, since it stops and switches the thread-state to
 * Thread::STATE_FAILURE when returning \b false.
 * In this case, startThread() method will return immediatly with a positive error code.
 * This architecture is very usefull because many object have to be allocated within
 * the new thread scope but the initialization may fail, so the thread should exit and report an error:
 * as easy as a "return false;" line.
 *
 *
 ****************************************************************************
 * @version 0.8.462 $Id: Thread.h 2839 2010-08-04 21:48:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ThreadS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Thread_H__
 #define __WOSH_Core_Thread_H__

 #include <woshDefs.h>
 #include <core/Mutex.h>
 #include <core/Reflection.h>


namespace wosh {

class Object;
class IThreadListener;
class ThreadManager;
class ThreadManagerMonitor;
template <class T> class DataFieldCollector;


class Thread : public virtual IReflection
 {
	WOSH_CLASSNAME(wosh::Thread)
	WOSH_CLASS_ABSTRACT(true)

	public:
		enum THREAD_STATE {
			STATE_UNKNOWN	= 0x00,
			STATE_CREATED	= 0x01,
			STATE_STARTING	= 0x02,
			STATE_RUNNING	= 0x03,
			STATE_STOPPING	= 0x04,
			STATE_STOPPED	= 0x05,
			STATE_DESTROYED	= 0x06,
			STATE_CRASHED	= 0x07,
			STATE_FAILURE	= 0x08
		 };

	public:
		Thread( const Object* owner, const std::string& threadName = "" );
		virtual ~Thread() { }

	public:
		virtual WRESULT startThread( unsigned long synch_timeout = LIMIT_ULONG_MAX ) = 0;

		virtual WRESULT quitThread( unsigned long synch_timeout = LIMIT_ULONG_MAX ) = 0;

		virtual bool waitThread( unsigned long time = LIMIT_ULONG_MAX ) = 0;

		virtual void terminateThread() = 0;

	public:
		virtual void crashDetected( double probability = 1.0 )	{ (void)probability; }

/** @name Static methods
 * @{
 ******************************************************************************/
	public:
		static bool waitState( const Thread* thread, Thread::THREAD_STATE state, unsigned long maxtime_msec = LIMIT_ULONG_MAX );
		static bool sleepWhile( const Thread* thread, unsigned long maxtime_msec = LIMIT_ULONG_MAX, unsigned long accurency_msec = 0, bool* semaphore0 = NULL, bool* semaphore1 = NULL );
		static bool sleepWhile( Thread* thread, unsigned long maxtime_msec = LIMIT_ULONG_MAX, unsigned long accurency_msec = 0, bool* semaphore0 = NULL, bool* semaphore1 = NULL );

//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline long getThreadID() const							{ return this->id; }
		inline const std::string& getThreadName() const			{ return this->threadname; }

		virtual bool isThreadRunning() const;

		bool isThreadAlive( long millisec_span = -1 ) const;
		inline long getThreadAliveTs() const					{ return this->aliveTs; }
		inline long getThreadAliveVariance() const				{ return this->aliveVariance; }

		inline IThreadListener* getListener() 					{ return this->threadListener; }
		inline const Object* getOwner() const					{ return this->ownerObj; }

		inline Thread::THREAD_STATE getThreadState() const		{ return this->threadState; }
		inline const char* getThreadStateAsString() const		{ return Thread::getThreadStateAsString(this->threadState); }

		static const char* getThreadStateAsString( Thread::THREAD_STATE State );
		static Thread::THREAD_STATE getThreadStateFromString( const char* State );

		static DataFieldCollector<Thread>* getDataFields();


//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		inline void setThreadName( const std::string& value )	{ this->threadname = value; }
		inline void setThreadListener( IThreadListener* list )	{ this->threadListener = list; }
		inline void setOwnerObject( const Object* list )		{ this->ownerObj = list; }

//@}
	protected:
		void setThreadID( long id );
		void setThreadState( Thread::THREAD_STATE state, bool raiseEvent = true );
		void setThreadAlive();

		bool waitForMSec( long millisec );

	protected:
		virtual bool isThreadRunningInternal() const = 0;

		virtual bool initializingThread()	{ return true; }
		virtual void runThread() = 0;
		virtual void exitingThread()		{ }


	protected:
		const Object* ownerObj;				///< owner of the thread, not required
		std::string threadname;				///< name of the thread, not required

		mutable bool running;				///< VERY IMPORTANT FLAG!
		mutable unsigned long aliveTs;		///< VERY IMPORTANT FLAG!
		mutable long aliveVariance;			///< how many milliseconds may pass between each alive-timestamping [default 10000]
		mutable MutexRW configurationLock;	///< mutex for configuration R/W

		IThreadListener* threadListener;	///< callbacks' listerner

	private:
		long id;
		mutable THREAD_STATE threadState;

	private:
		friend class ThreadManager;			///< let my manager access protected functions
		friend class ThreadManagerMonitor;	///< let my manager's helper access protected functions

}; // class def


class IThreadListener {
	public:
		virtual void thread_event( Thread::THREAD_STATE thread_event, Thread* thread_source ) = 0;

	public:
		virtual ~IThreadListener() { }

}; // class def

}; // namespace wosh


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if defined(USE_PTHREAD)
# include <core/posix/pthread_thread.h>
# define _THREAD_ARCH	"pthread"
namespace wosh {
 typedef class ThreadImpl_PThread ThreadImpl;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#elif defined(USE_THREAD_WIN32)
# include <core/win32/win32_thread.h>
# define _THREAD_ARCH	"win32-native"
namespace wosh {
 typedef class ThreadImpl_Win32Thread ThreadImpl;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else //if defined(USE_THREAD_QT)
# include <QThread>
# define _THREAD_ARCH	"qt"
namespace wosh {
class ThreadImpl_QThread :	protected QThread,
							public wosh::Thread
 {
	WOSH_CLASSNAME(wosh::ThreadImpl) // faking classname cos of typedef
	WOSH_CLASS_ABSTRACT(true)

	public:
		/**
		 * @brief   Initialize thread and register thread to global list
		 * @param owner [in] owner of the thread, may be NULL. Used for debug/log purpose (and not instance-ownership)
		 * @param threadName [in] optional name of the thread, may be empty.. Used for debug/log purpose
		 * @see     wosh::ThreadManager
		 */
		ThreadImpl_QThread( const wosh::Object* owner, const std::string& threadName = "" );
		/**
		 * @brief   unregister thread from global list
		 * @see     wosh::ThreadManager
		 */
		virtual ~ThreadImpl_QThread();

	public:
		virtual WRESULT startThread( unsigned long synch_timeout = LIMIT_ULONG_MAX );
		virtual WRESULT quitThread( unsigned long synch_timeout = LIMIT_ULONG_MAX );
		bool waitThread( unsigned long time = LIMIT_ULONG_MAX );
		void terminateThread();

	public:
		static inline void sleepForSec( int sec )				{ sleep(sec); }
		static inline void sleepForMSec( int msec )				{ msleep(msec); }

	protected:
		bool isThreadRunningInternal() const;

	private:
		virtual void run();

 }; // class def
 typedef class ThreadImpl_QThread ThreadImpl;

}; // namespace wosh

#endif // else/_THREAD_QT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


#endif //__WOSH_Core_Thread_H__
